//
// Created by denglibin on 2021/4/7 0007.
//

#include "MainWindow.h"
#include <iostream>

using namespace std;
MainWindow::MainWindow(int width, int height, std::string &title): Window(width, height, title){
    initOpenGLObj();
}
MainWindow::~MainWindow(){
    delete shader;
    glDeleteVertexArrays(1, &objectVAO);
    glDeleteBuffers(1, &VBO);
}
/**
 * 循环绘制
 */
void MainWindow::paint() {
    //设置清除颜色
    glClearColor(0, 0, 0, 1.0f);
    //使用上面设置的颜色清空屏幕
    // glClear(GL_COLOR_BUFFER_BIT);
    //因为使用了深度测试，我们也想要在每次渲染迭代之前清除深度缓冲（否则前一帧的深度信息仍然保存在缓冲中）。就像清除颜色缓冲一样
    glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);

    //调用glUseProgram函数，用刚创建的程序对象作为它的参数，以激活这个程序对象
    shader->use();
    setUniform();
    glActiveTexture(GL_TEXTURE0);
    glBindTexture(GL_TEXTURE_2D, texture);
    glActiveTexture(GL_TEXTURE1);
    glBindTexture(GL_TEXTURE_2D, texture);

    //设置模型观察和投影矩阵
    viewMat();
    projectionMat();
    //绑定物体VAO
    glBindVertexArray(objectVAO);
    glm::vec3 rotateV = {1.0f, 0.3f, 0.5f};

   //画10次
    for(int i = 0; i < 10; i++){
        //设置平移位置和旋转角度
        modelMat((float )i * 20.0f * (float )(i+1), rotateV, cubePositions[i]);
        glDrawArrays(GL_TRIANGLES, 0, 36);
    }
    glBindVertexArray(0);
}
/**
 * 初始化opengl相关
 */
void::MainWindow::initOpenGLObj(){
    string vertexPath = R"(D:\CLionProjects\opengl-mingw\shader2\shader5_object.vs)";
    string fragmentPath = R"(D:\CLionProjects\opengl-mingw\shader2\shader5_object.fs)";
    //创建着色器程序
    shader = new Shader(vertexPath, fragmentPath);
    VBO = createVBO(vertices, sizeof (vertices) / sizeof (float ));
    //创建物体的VAO
    objectVAO = createVAO();
    setVertexAttr();
    //创建纹理
    texture = createTexture(R"(D:\CLionProjects\opengl-mingw\img\container2.png)", GL_RGBA, GL_RGBA);

}

void::MainWindow::setVertexAttr(){
    //顶点位置
    glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 8 * sizeof(float), (void*)nullptr);
    glEnableVertexAttribArray(0);

    //法向量
    glVertexAttribPointer(1, 3, GL_FLOAT, GL_FALSE, 8 * sizeof(float), (void*) (3 * sizeof(float)));
    glEnableVertexAttribArray(1);

    //纹理
    glVertexAttribPointer(2, 2, GL_FLOAT, GL_FALSE, 8 * sizeof(float), (void*) (6 * sizeof(float)));
    glEnableVertexAttribArray(2);
}

void::MainWindow::setUniform(){
    //材质变量
    glm::vec3 material_ambient = {1.0f, 0.5f, 0.31f}; //在环境光照下这个物体反射得是什么颜色，通常这是和物体颜色相同的颜色
    glm::vec3  material_diffuse = {1.0f, 0.5f, 0.31f}; //在漫反射光照下物体的颜色。（和环境光照一样）漫反射颜色也要设置为我们需要的物体颜色
    glm::vec3  material_specular = {0.5f, 0.5f, 0.5f}; //镜面光照对物体的颜色影响
    float  material_shininess= 32.0f; //影响镜面高光的散射/半径

    //光源变量
    glm::vec3  light_ambient = {0.2f, 0.2f, 0.2f}; //环境光照通常会设置为一个比较低的强度，因为我们不希望环境光颜色太过显眼
    glm::vec3  light_diffuse = {0.5f, 0.5f, 0.5f}; //漫反射分量通常设置为光所具有的颜色，通常是一个比较明亮的白色; 将光照调暗了一些以搭配场景
    glm::vec3  light_specular = {1.0f, 1.0f, 1.0f}; //镜面光分量通常会保持为vec3(1.0)，以最大强度发光
    glm::vec3  light_direction = {-1.0f, 0.0f, 0.0f}; //光方向 x轴负方向（从右往左）
    glm::vec3 objectColor = {1.0f, 0.5f, 0.31f}; //物体颜色
    glm::vec3 lightColor = { 1.0f, 1.0f, 1.0f}; //灯颜色

    shader->setVec3("lightColor", lightColor);
    shader->setVec3("objectColor", objectColor);
    shader->setVec3("viewPos", camera->cameraPos );

    //设置材质变量
    shader->setVec3( "material.ambient",  material_ambient);
    shader->setFloat(  "material.shininess", material_shininess);

    //设置光源变量
    shader->setVec3( "light.ambient",  light_ambient);
    shader->setVec3( "light.diffuse",  light_diffuse);
    shader->setVec3( "light.specular", light_specular);
    shader->setVec3( "light.direction", light_direction);
    shader->setVec3( "light.lightColor", lightColor);

    //材质漫反射颜色分量 使用纹理
    shader->setInt("material.diffuse", 0);
    //材质镜面反射颜色分量 使用纹理
    shader->setInt("material.specular", 1);
}
void MainWindow::viewMat(){
    //摄像机位置 + 摄像机方向 = 目标位置
    //LookAt函数需要一个位置、目标和上向量
    glm::mat4 view  = glm::lookAt(camera->cameraPos,
                                      camera->cameraPos + camera->cameraFront,
                                      camera->cameraUp);

    shader->setMatrix4fv("view", view);
}
void MainWindow::projectionMat(){
    glm::mat4 proj = glm::perspective(glm::radians(camera->fovY), (float)width/(float)height, 0.1f, 100.0f);
    shader->setMatrix4fv("projection", proj);
}

void MainWindow:: modelMat(float angel, glm::vec3 rotateV, glm::vec3 translateV){
    //GLM库从0.9.9版本起，默认会将矩阵类型初始化为一个零矩阵（所有元素均为0），而不是单位矩阵（对角元素为1，其它元素为0）。
    // 如果你使用的是0.9.9或0.9.9以上的版本，你需要将所有的矩阵初始化改为 glm::mat4 mat = glm::mat4(1.0f)
    glm::mat4 model = glm::mat4(1.0f);
    model = glm::translate(model, translateV);
    model = glm::rotate(model, glm::radians(angel), rotateV);
    shader->setMatrix4fv("objectModel", model);
}


